<?php
	/**
	 * <version greek="beta" major="1" minor="0">Cochin Splash Hen</version>
	 * <author email="njones@art-k-tec.com">Nika Jones</author>
	 * <copyright start="2007">Art-k-tec Systems, LLC</copyright>
	 * <license type="Apache2.0" href="http://www.opensource.org/licenses/apache2.0.php">Apache License, Version 2.0</license>
	 * <summary>
	 * 	All of the classes are included within this file. You can extract the classes that are needed.
	 * 	It's extra overhead for file downloads but it makes the file fully self-sufficent. You can always override
	 * 	with a newer version of the locked class. and the class can include the auto-lib update
	 * <summary>
	 */
	
	/**
	 * <summary>
	 *	The exceptions 
	 * </summary> 
	 */
	class bArrayException extends Exception {
		const INVALID_TYPE			=10000;
	}
	
	/// <summary>
	///    The interface which can tell if this is an bArray or not
	///    for casting purposes
	/// </summary>
	interface IbArray {
		
		/// <summary>
		///   returns the array formally
		/// </summary>
		public function AsArray();
		
		/// <summary>
		///   returns the array as an XML node
		/// </summary>
		public function AsXml();
	}
	
	/// <summary>
	///		The array with built in XML capabilities. Also provides a standard interface for array behaviours
	/// </summary>
	class bArray extends ArrayObject {
		private static $nMajor =1;
		private static $nMinor =0;
		private static $sRevision ="0000";
		
		const DEFAULT_NODE_NAME		='array';
		
		const TO_UPPER 		=1;
		const TO_LOWER 		=2;
		const RECURSIVE 	=4;

		const KEY			=8;
		const REVERSE		=16;
		const ASSOC			=32;
		const SORT			=64;

		const SORT_REGULAR 			=128;
		const SORT_NUMERIC 			=512;
		const SORT_STRING 			=1024;
		const SORT_LOCALE_STRING 	=2048;
		
		/// <summary>
		///		Allows for you to "copy" an array by value, or create a new array object
		/// </summary>
		public function __construct($mValue =array()) {
			
			if(is_string($mValue)) {
				
				$aValue =array($mValue);
			} elseif($mValue ==null) {

				$aValue =array();
			} else {
				
				$aValue =$mValue; //asuming array (otherwise let PHP error handling do the work.)
			}
			
			parent::__construct($aValue);
		}
		
		public static function version() { return self::$nMajor.'.'.self::$nMinor.'.'.self::$sRevision; }
		
		/// <summary>
		/// 	<encapsulate>array_chunk</encapsulate>
		/// </summary>
		/// <param type="int" name="nSize">The size of the array chunks</param>
		/// <param type="bool" name="bPreserveKeys" optional="true">Set this to <true /> to keep the keys</param>
		/// <returns type="bArray">The current bArray object with the new chunked values</returns>
		public function Chunk($nSize, $bPreserveKeys =null) {
			
			parent::__construct(array_chunk((array)$this, $nSize, $bPreserveKeys));
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>in_array</encapsulate>
		/// 	Provides a nice name (an a more common one at that) name for finding values in an array
		/// </summary>
		/// <param type="string" name="sNeedle">The value searched for</param>
		/// <param type="bool" name="bStrict">Allows for variance in the search method</param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Contains($sNeedle, $bStrict =false) {
			
			return in_array($sNeedle, (array)$this, $bStrict);
		}
		
		/// <summary>
		/// 	<encapsulate>count($this)</encapsulate>
		/// </summary>
		/// <returns type="int">The current count of the objects</returns>
		public function Count() {
			
			return count((array)$this);
		}
		
		/// <summary>
		/// 	<encapsulate>array_count_values</encapsulate>
		/// </summary>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function CountValues() {
			
			parent::__construct(array_count_values((array)$this));
			return $this;
		}
		
		/// <summary>
		///  returns the diff of the array
		/// </summary>
		public function Diff() {
			
				$aArgument =func_get_args();
				array_unshift($aArgument, (array)$this);
				
				parent::__construct(call_user_func_array('array_diff', $aArgument));
				return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>extract</encapsulate>
		/// </summary>
		/// <param type="constant" name="cType" optional="true">How to extract the variables</param>
		/// <param type="bool" name="bStrict" optional="true">prefix on the extracted variable</param>
		public function Extract($cType =null, $sPrefix ='') {
			
			return extract((array)$this, $cType, $sPrefix);
		}
		
		/// <summary>
		/// 	<encapsulate>array_filter</encapsulate>
		/// </summary>
		/// <param type="function" name="fCallback" optional="true">The callback to use for the filter</param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Filter($fCallback =null) {
			
			parent::__construct(array_filter((array)$this, $fCallback));
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>array_flip</encapsulate>
		/// </summary>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Flip() {
			
			parent::__construct(array_flip((array)$this));
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>implode</encapsulate>
		/// </summary>
		/// <param type="string" name="sSeparator">The string used to seperate the array values</param>
		/// <returns type="string" />
		public function Implode($sSeparator) {
			
			return implode($sSeparator, (array)$this);
		}
		
		/// <summary>
		/// 	<encapsulate>array_change_key_case</encapsulate>
		/// </summary>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function KeyCase() {
			$aArgument =func_get_args();
			$nArgument = self::Reduce($aArgument);

			switch(true) {

				case self::TO_UPPER & $nArgument:
					parent::__construct(array_change_key_case((array)$this, CASE_UPPER));
				break;
				default:
					parent::__construct(array_change_key_case((array)$this, CASE_LOWER));
				break;
			}

			return $this;	
		}
		
		/// <summary>
		/// 	<encapsulate>array_key_exists</encapsulate>
		/// </summary>
		/// <param type="string" name="sKeyName">The value searched for</param>
		/// <returns type="bool" />
		public function KeyExists($sKeyName) {
			
			return array_key_exists($sKeyName, (array)$this);
		}
		
		/// <summary>
		/// 	<encapsulate>array_keys</encapsulate>
		/// </summary>
		/// <param type="string" name="sSearchValue">The value searched for</param>
		/// <param type="bool" name="bStrict">Allows for variance in the search method</param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Keys($sSearchValue =null, $bStrict =false) {
			
			parent::__construct(array_keys((array)$this, $sSearchValue, $bStrict));
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>array_map</encapsulate>
		/// </summary>
		/// <param type="function" name="fCallback">The function used to filter data through</param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Map($fCallback) {
			$aArgument =func_get_args();
			$fCallback =array_shift($aArgument); // Triming the argumentlist as it should be.
			
			// make sure that you add this array to the map.
			array_unshift($aArgument, (array)$this);
			
			parent::__construct(call_user_func_array("array_map", $aArgument));
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>array_merge</encapsulate>
		/// 	<encapsulate>array_merge_recursive</encapsulate>
		/// </summary>
		/// <param type="constant">Determines how the array should be merged</param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Merge() {
			$aMerge =array();
			$bRecursive =false;
			
			$aArgument =func_get_args();
			
			foreach($aArgument as $mArgument) {
				
				switch($mArgument) {
					
					case self::RECURSIVE:
						$bRecursive =true;
					break;
					default:
						$aMerge[] = $mArgument;
					break;
				}
			}
			
			array_unshift($aMerge, (array)$this);
			
			if($bRecursive) {
				
				parent::__construct(call_user_func_array("array_merge_recursive", $aMerge));
				return $this;
			} else {
				
				parent::__construct(call_user_func_array("array_merge", $aMerge));
				return $this;
			}
		}
		
		/// <summary>
		/// 	<encapsulate>array_pad</encapsulate>
		/// </summary>
		/// <param type="int" name="nSize">The final size of the array</param>
		/// <param type="mixed" name="mValue">The values used to pad the array</param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Pad($nSize, $mValue ='') {
			
			parent::__construct(array_pad((array)$this, $nSize, $mValue));
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>array_pop</encapsulate>
		/// </summary>
		/// <returns type="mixed">The value of the last item in the array</returns>
		public function Pop() {
			
			$a =(array)$this;
			$m =array_pop($a);
			
			return $m;
		}
		
		/// <summary>
		/// 	<encapsulate>array_product</encapsulate>
		/// </summary>
		/// <returns type="int">The product of all items in the array</returns>
		public function Product() {
			
			return array_product((array)$this);
		}
		
		/// <summary>
		/// 	<encapsulate>array_push</encapsulate>
		/// </summary>
		/// <param type="mixed" name="mValue">The value to be added at the end of the array</param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Push($mValue) {
			
			$a = (array)$this;
			array_push($a, $mValue);
			
			parent::__construct($a);
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>array_rand</encapsulate>
		/// </summary>
		/// <param type="int" name="nNumber" optional="true">The number of random values to return</param>
		/// <returns type="bArray">
		///		The current bArray object with the new values
		///		<note>Will always return an array, even with one value</note>
		/// </returns>
		public function Rand($nNumber =1) {
			
			$this->__construct(array_rand((array)$this), $nNumber);
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>range</encapsulate>
		/// </summary>
		/// <param type="mixed" name="nStart">The value start the range with</param>
		/// <param type="mixed" name="nEnd">The value to end the range with</param>
		/// <param type="int" name="nStep">The number of steps between increments</param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Range($nStart, $nEnd, $nStep =1) {
			
			parent::__construct(range($nStart, $nEnd, $nStep));
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>array_reduce</encapsulate>
		/// </summary>
		/// <param type="function" name="fCallback">The callback to filter results through</param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Reduce($fCallback) {
			
			$aArgument =func_get_args();
			array_unshift($aArgument, (array)$this);
			
			parent::__construct(call_user_func_array("array_reduce", $aArgument));
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>array_reverse</encapsulate>
		/// </summary>
		/// <param type="bool" name="bPreserveKeys" optional="true">Key the keys or not.</param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Reverse($bPreserveKeys =false) {
			
			parent::__construct(array_reverse((array)$this, $bPreserveKeys));
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>array_search</encapsulate>
		/// </summary>
		/// <param type="string" name="sNeedle">The value searched for</param>
		/// <param type="bool" name="bStrict">Allows for variance in the search method</param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Search($sNeedle, $bStrict =false) {
			
			parent::__construct(array_search($sNeedle, (array)$this, $bStrict));
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>array_shift</encapsulate>
		/// </summary>
		/// <returns type="mixed">The first item of the array</returns>
		public function Shift() {
			
			$a =(array)$this;
			$m =array_shift($a);
			
			return $m;
		}
		
		/// <summary>
		/// 	<encapsulate>array_slice</encapsulate>
		/// </summary>
		/// <param type="int" name="nOffset">The start index of the array to slice</param>
		/// <param type="int" name="nLength" optional="true">The length of the slice</param>
		/// <param type="bool" name="bPreserveKeys" optional="true">Keep the keys when slicing</param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Slice($nOffset, $nLength =null, $bPreserveKeys =false) {
			
			$nLength =($nLength ==null ? count((array)$this) - $nOffset : $nLength);
			
			parent::__construct(array_slice((array)$this, $nOffset, $nLength, $bPreserveKeys));
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>sort</encapsulate>
		/// 	<encapsulate>asort</encapsulate>
		/// 	<encapsulate>ksort</encapsulate>
		/// 	<encapsulate>rsort</encapsulate>
		/// 	<encapsulate>arsort</encapsulate>
		/// 	<encapsulate>krsort</encapsulate>
		/// </summary>
		/// <param type="constant" name="...">Detrmines the mix of sorting needed/param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Sort($nbArray =null) { // You should pass in all of the parameters you need, like reverse and all that jazz.
			
			$a =(array)$this;
			$aArgument =func_get_args();
			$nArgument =0;
			
			foreach($aArgument as $nBitwise) {
				$nArgument =$nArgument | $nBitwise;
			}
			
			$mSORT_REGULAR =$mSORT_NUMERIC =$mSORT_STRING =$mSORT_LOCALE_STRING =null;
			
			if(self::SORT_REGULAR & $nArgument) {
				
				$mSORT_REGULAR =0;
			}
			
			if(self::SORT_NUMERIC & $nArgument) {
				
				$mSORT_NUMERIC =1;
			}
			
			if(self::SORT_STRING & $nArgument) {
				
				$mSORT_STRING =2;
			}
			
			if(self::SORT_LOCALE_STRING & $nArgument) {
				
				$mSORT_LOCALE_STRING =3;
			}
			
			if((self::ASSOC & $nArgument) && (self::REVERSE & $nArgument)) {
				
				arsort($a);
				parent::__construct($a);
				
			} elseif((self::KEY & $nArgument) && (self::REVERSE & $nArgument)) {
				
				krsort($a);
				parent::__construct($a);
			} else {
				
				if(self::KEY & $nArgument) {
					
					ksort($a);
					parent::__construct($a);
				}
				
				if(self::ASSOC & $nArgument) {
					
					asort($a);
					parent::__construct($a);
				}
				
				if(self::REVERSE & $nArgument) {
					
					rsort($a);
					parent::__construct($a);
				}
			}
			
			if($nbArray ==null || $nbArray ==self::SORT || $nbArray ==self::SORT_REGULAR || $nbArray ==self::SORT_NUMERIC || $nbArray ==self::SORT_STRING || $nbArray ==self::SORT_LOCALE_STRING) {
				$nFlag =($mSORT_REGULAR + $mSORT_NUMERIC + $mSORT_STRING + $mSORT_LOCALE_STRING);
				rsort($a, $nFlag);
			}
				
			parent::__construct($a);
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>array_splice</encapsulate>
		/// </summary>
		/// <param type="int" name="nOffset">The index offset to start at</param>
		/// <param type="int" name="nLength" optional="true">The length of the splice</param>
		/// <param type="array" name="aReplace" optional="true">
		/// 	The spliced array to insert in the middle of the array
		/// </param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Splice($nOffset, $nLength =null, $aReplace =array()) {
			
			$a =(array)$this;
			$nLength =($nLength ==null ? count((array)$this) - $nOffset : $nLength);
			$a2 = array_splice($a, $nOffset, $nLength, $aReplace);
			
			parent::__construct($a2);
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>array_sum</encapsulate>
		/// </summary>
		/// <returns type="int">The sum of all of the values in the array</returns>
		public function Sum() {
			
			return array_sum((array)$this);
		}
		
		/// <summary>
		/// 	<encapsulate>array_unique</encapsulate>
		/// </summary>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Unique() {
			
			parent::__construct(array_unique((array)$this));
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>array_unshift</encapsulate>
		/// </summary>
		/// <param type="mixed" name="mValue">The value to add to the array</param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Unshift($mValue) {
			
			$a =(array)$this;
			$a2 =array_unshift($a, $mValue);
			
			parent::__construct($a2);
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>array_values</encapsulate>
		/// </summary>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function Values() {
			
			parent::__construct(array_values((array)$this));
			return $this;
		}
		
		/// <summary>
		/// 	<encapsulate>array_walk</encapsulate>
		/// </summary>
		/// <param type="function" name="fCallback">The function used to filter the results of the values</param>
		/// <param type="mixed" name="..." optional="true">The values to pass to the callback function</param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		/// <todo>Add the recursive array walk function</todo>
		public function Walk($fCallback, $mData =null) {
			
			$a =(array)$this;
			array_walk($a, $fCallback, $mData);
			
			parent::__construct($a);
			return $this;
		}
		
		/// <summary>
		/// 	Returns the array as a well-formed XML object
		/// </summary>
		/// <returns type="string">The current bArray object as a Xml</returns>
		public function AsXml() {
			$aData =(array)$this;
			
			if(!is_array($aData[key($aData)])) { $aData[self::DEFAULT_NODE_NAME] =$aData; }
			if(count($aData) > 1) { $aData[self::DEFAULT_NODE_NAME] =$aData; }
			
			$oReturn = new XmlWriter();
			
			$oReturn->openMemory();
			$oReturn->startDocument('1.0', 'UTF-8');
			$this->_AsXml($oReturn, $aData);
			
			return $oReturn->outputMemory();
		}

		/// <summary>
		/// 	The actual XML method that does all of the work.
		/// </summary>
		/// <param type="XMLWriter" name="oXmlWriter" />
		/// <param type="array" name="aData">The array to transform into an XML object</param>
		/// <returns type="XMLWriter" />
		private function _AsXml(XMLWriter $oXmlWriter, array $aData){
			foreach($aData as $sKey =>$mValue)
			{
				$ElementName = is_numeric((string)$sKey) ? "_".$sKey : $sKey;

				if(is_array($mValue)){
					$oXmlWriter->startElement($ElementName);
					$this->_AsXml($oXmlWriter, $mValue);
					$oXmlWriter->endElement();
				}
				elseif(is_scalar($mValue))
				{	
					switch(true) {
						case ((string)$sKey[0] == "@"):
							$oXmlWriter->writeAttribute(substr($sKey,1), $mValue);
						break;
						default:
							$oXmlWriter->startElement($ElementName);
							$oXmlWriter->text($mValue);
							$oXmlWriter->endElement();
						break;
					}
				}
			}

			return $oXmlWriter;
		}

		/// <summary>
		/// 	Removes a key from the array
		/// </summary>
		/// <param type="mixed" name="mData">Either a string or array of keys to remove</param>
		/// <returns type="bArray">The current bArray object with the new values</returns>
		public function DeleteKey($mData) {
			
			if(is_array($mData)) {
				
				foreach($mData as $mValue) {
					if(is_array($mValue)) { 
						$this->DeleteKey($mValue); 
					} else {
						unset($this[$mValue]);
					}
				}
			} else {
				
				unset($this[$mData]);
			}
		}
		
		/// <summary>
		/// 	Provides object oriented access to the index of an array. Also allows numeric access
		/// 	to non-numeric keys
		/// </summary>
		/// <param type="int" name="nKey">The number of the key to return</param>
		/// <returns type="mixed">The value of the index passed</returns>
		public function Item($nKey) {
			if(!is_numeric($nKey)) {
				throw new bArrayException(
					'You must pass a numeric number to this function. ',
				bArrayException::INVALID_TYPE);
			}
			
			if($nKey > (count($this) -1)) {
				throw new bArrayException(
					'You have supplied an index beyond the bounds of this array. ',
				bArrayException::INVALID_INDEX);
			}
			
			$nCounter =0;
			foreach($this as $sKey =>$sValue) {
				if($nCounter == (int)$nKey) {
					return $sValue;
				}
			}
		}
		
		// Private Functions
		///<summary>
		///   Sniffs an array to see if it's a list of values based on the index.
		///</summary>
		///<param type="array" name="aValue">The array to check</param>
		///<returns type="bool">Whether the array is percived to be a list or not</returns> 
		private function IsList(array $aValue) {
			return array_keys($aValue) ==range(0, count($aValue)-1);
		}
		
		private function FlattenArray(array $a, $c =self::VALUE) {
			
			$aReturn =array();
			foreach($a as $sKey =>$mValue) {
				$aReturn =(is_array($mValue) ? 
					array_merge($aReturn, self::FlattenArray($mValue, $c)) : $aReturn +array($sKey=>$mValue)
				);
			}

			return ($c ==self::VALUE ? array_values($aReturn) : array_keys($aReturn));
		}
		
		///<summary>
		///   Used to lowercase all of the values within an array
		///</summary>
		///<param type="string" name="sValue">the value to lowercase</param>
		///<returns type="string" />
		private function ToLower($sValue) {
			return strtolower($sValue);
		}
		
		///<summary>
		///   Used to uppercase all of the values within an array
		///</summary>
		///<param type="string" name="sValue">the value to uppercase</param>
		///<returns type="string" />
		private function ToUpper($sValue) {
			return strtoupper($sValue);
		}
		
		///<summary>
		///   Returns the array as a comma delimated string
		///</summary>
		///<returns type="string" />
		public function __toString() {
			return "'".$this->Implode("', '")."'";
		}
	}
?>

<?php /* include_once("../functions/bEasyResourceManager.php"); */ return; ?>
<bResourceManager version="1.01" />